//!
/**
***********************************************************************************************************
* <RBDAEReader Implementation>
***********************************************************************************************************
* @file RBDAEReader.cpp
***********************************************************************************************************/

/***********************************************************************************************************
* Precompiled Header
***********************************************************************************************************/
#include "RBMainPCH.h"


/***********************************************************************************************************
* Includes
***********************************************************************************************************/
#include "RBDAEReader.h"

#include "RBCamera.h"
#include "RBEntity.h"
#include "RBFile.h"
#include "RBGeometry.h"
#include "RBHandle.h"
#include "RBHardwareBufferManager.h"
#include "RBIndexData.h"
#include "RBLight.h"
#include "RBMath.h"
#include "RBProfiler.h"
#include "RBRenderer.h"
#include "RBResourceManager.h"
#include "RBVertexData.h"
#include "RBVertexElement.h"

#include "RBRenderProcess/RBEffectFactory.h"

#include "RBMemoryManagerOff.h"
    #pragma warning(push)
    #pragma warning(disable: 4996)
    #undef UNUSED
    #include <FCollada/FCollada.h>
    #include <FCollada/FCDocument/FCDocument.h>
    #include <FCollada/FCDocument/FCDCamera.h>
    #include <FCollada/FCDocument/FCDController.h>
    #include <FCollada/FCDocument/FCDControllerInstance.h>
    #include <FCollada/FCDocument/FCDEffect.h>
    #include <FCollada/FCDocument/FCDEffectParameterSampler.h>
    #include <FCollada/FCDocument/FCDEffectStandard.h>
    #include <FCollada/FCDocument/FCDLibrary.h>
    #include <FCollada/FCDocument/FCDGeometry.h>
    #include <FCollada/FCDocument/FCDGeometryInstance.h>
    #include <FCollada/FCDocument/FCDGeometryMesh.h>
    #include <FCollada/FCDocument/FCDGeometrySource.h>
    #include <FCollada/FCDocument/FCDGeometryPolygons.h>
    #include <FCollada/FCDocument/FCDGeometryPolygonsInput.h>
    #include <FCollada/FCDocument/FCDImage.h>
    #include <FCollada/FCDocument/FCDLight.h>
    #include <FCollada/FCDocument/FCDMaterial.h>
    #include <FCollada/FCDocument/FCDMaterialInstance.h>
    #include <FCollada/FCDocument/FCDSceneNode.h>
    #include <FCollada/FCDocument/FCDTexture.h>
    #pragma warning(pop)
#include "RBMemoryManagerOn.h"

/***********************************************************************************************************
* Defines
***********************************************************************************************************/

/***********************************************************************************************************
* Classes implementation
***********************************************************************************************************/

template<uint32 uiDim, class RBVector, class FCDVector> RBVector Convert(const FCDVector& fcd)
{
    RBVector rb;
    memcpy_s(&rb.Data[0], uiDim * sizeof(float32), &fcd.x, uiDim * sizeof(float32));
    return rb;
}


/**
***********************************************************************************************************
* Constructor
***********************************************************************************************************/
RBDAEReader::RBDAEReader()
{
    FCollada::Initialize();
}

/**
***********************************************************************************************************
* Destructor
***********************************************************************************************************/
RBDAEReader::~RBDAEReader()
{
    FCollada::Release();
}

#pragma TODO("Correct DAE Loading now that there is no database anymore")
/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
RBStream* RBDAEReader::Load(const RBString& strFilename)
{
    RBRenderer* pRenderer = RBRenderer::GetSingleton();
    RBStream* pStream = 0;

    bool bLoadSuccessful = false;
    {
        RB_PROFILE("RBDAEReader::Load");

        FUObjectRef<FCDocument> pDocument = FCollada::NewTopDocument();
        if ((bLoadSuccessful = FCollada::LoadDocumentFromFile(pDocument, strFilename.c_str())) == true)
        {
            RB_PROFILE("RBDAEReader::Load::RB Part");
            pStream = new RBStream;
            RBEntityHandle pRoot = RBEntity::CreateEntity();
            pStream->Insert(pRoot);
            ParseLibraries(pDocument, pRenderer);
            {
                FCDVisualSceneNodeLibrary* pVisualSceneNodeLibrary = pDocument->GetVisualSceneLibrary();
                for (uint32 uiNode=0; uiNode<pVisualSceneNodeLibrary->GetEntityCount(); ++uiNode)
                {
                    CreateObjectFromNode(pVisualSceneNodeLibrary->GetEntity(uiNode), pRenderer, pRoot, InvalidHandle);
                }
            }
            
            RBTransformComponent::UpdateEntity(pRoot);
            RBBVolume::UpdateEntity(pRoot);

            m_mGeometries.clear();
            m_mMaterials.clear();
        }
    }

    RBString strProfile;
    for (uint32 ui=0; ui < RBProfilerManager::GetSingleton()->Profilers.size(); ++ui)
    {
        RBProfiler* pProfiler = RBProfilerManager::GetSingleton()->Profilers[ui];
        strProfile += RBStringTools::FormatString("%s: %d\n", pProfiler->GetBlockName(), pProfiler->GetDuration());
    }

    OutputDebugStringA(strProfile.c_str());

    return pStream;
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void RBDAEReader::CreateObjectFromNode(const FCDSceneNode* pNode, RBRenderer* pRenderer, RBEntityHandle entityHandle, RBTransformComponentHandle xFormParent)
{
    RBEntity& entity = RBEntity::Get(entityHandle);
    RBTransformComponentHandle xFormHandle = RBTransformComponent::Create(entityHandle);

    if (xFormParent != InvalidHandle)
    {
        RBTransformComponent::Get(xFormParent).AddChild(xFormHandle);
    }

    RBTransformComponent& xForm = RBTransformComponent::Get(xFormHandle);
    entity.AddComponent<RBTransformComponent>(xFormHandle);

    RBTransform& localXForm = xForm.LocalXForm();
    FMMatrix44 srcMatLocal= pNode->ToMatrix();
    FMVector3 scale; FMVector3 rotation; FMVector3 translation; float inverted;
    srcMatLocal.Decompose(scale, rotation, translation, inverted);
    localXForm.Translate.x = translation.x;
    localXForm.Translate.y = translation.y;
    localXForm.Translate.z = translation.z;

    float3x3 rotX, rotY, rotZ;
    rotX.SetXRotation(rotation.x);
    rotY.SetYRotation(rotation.y);
    rotZ.SetZRotation(rotation.z);

    localXForm.Rotate = rotZ * rotY * rotX;

    localXForm.Rotate = localXForm.Rotate.Transpose();

    localXForm.Scale.x = scale.x;
    localXForm.Scale.y = scale.y;
    localXForm.Scale.z = scale.z;

    // Analyse all instances attached to geometry and attach them first
    for (uint32 uiInstance = 0; uiInstance<pNode->GetInstanceCount(); ++uiInstance)
    {
        const FCDEntityInstance* pInstance = pNode->GetInstance(uiInstance);
        switch(pInstance->GetEntityType())
        {
        case FCDEntity::GEOMETRY:
            AddGeometryInstance(entityHandle, xFormHandle, (FCDGeometry*)((FCDGeometryInstance*)pInstance)->GetEntity(), ((FCDGeometryInstance*)pInstance));
            break;
        case FCDEntity::CAMERA:
            AddCamera(entityHandle, xFormHandle, (FCDCamera*)pInstance->GetEntity());
            break;
        case FCDEntity::LIGHT:
            AddLight(entityHandle, xFormHandle, (FCDLight*)pInstance->GetEntity());
            break;
        case FCDEntity::CONTROLLER:
            {
                FCDControllerInstance* pFCDSkin = (FCDControllerInstance*)pInstance;
                FCDController* pFCDSkinEntity = (FCDController*)pFCDSkin->GetEntity();
                AddGeometryInstance(entityHandle, xFormHandle, pFCDSkinEntity->GetBaseGeometry(), pFCDSkin);
            }
            break;
        default:
            RBAssert(false, "Unsupported type");
            break;
        }
    }


    for (uint32 uiChild = 0; uiChild < pNode->GetChildrenCount(); ++uiChild)
    {
        CreateObjectFromNode(pNode->GetChild(uiChild), pRenderer, entityHandle, xFormHandle);
    }

}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void RBDAEReader::ParseLibraries(FCDocument* pDocument, RBRenderer* pRenderer)
{
    const FCDMaterialLibrary* pMatLib = pDocument->GetMaterialLibrary();
    for (uint32 uiMaterial = 0; uiMaterial < pMatLib->GetEntityCount(); ++uiMaterial)
    {
        CreateMaterialFromMaterial(pMatLib->GetEntity(uiMaterial), pRenderer);
    }

    const FCDGeometryLibrary* pGeomLib = pDocument->GetGeometryLibrary();
    for (uint32 uiGeom = 0; uiGeom < pGeomLib->GetEntityCount(); ++uiGeom)
    {
        CreateObjectFromGeometry(pGeomLib->GetEntity(uiGeom), pRenderer);
    }

}

struct VertexIndexedData
{
    const FCDGeometryPolygons* Polygons;
    uint32*  DaeIndices;
    uint32   DaeIndexCount;
    uint16   RBIndex;
    uint16   PolygonIndex : 15;
    bool     Duplicate : 1;

    static const uint16 InvalidRBIndex = 0xFFFF;

    VertexIndexedData() 
    {
        Polygons = 0;
        DaeIndices = 0; 
        DaeIndexCount = 0;
        RBIndex = InvalidRBIndex;
        Duplicate = true;
    }

    ~VertexIndexedData() 
    {
    }

    bool operator < (const VertexIndexedData& rhs) const
    {
        if (PolygonIndex != rhs.PolygonIndex)
        {
            return PolygonIndex < rhs.PolygonIndex;
        }

        for (uint32 ui=0; ui < DaeIndexCount; ++ui)
        {
            uint32 uiThisIdx = DaeIndices[ui];
            uint32 uiRHSIdx = rhs.DaeIndices[ui];
            if (uiThisIdx < uiRHSIdx)
            {
                return true;
            }
            else if (uiThisIdx > uiRHSIdx)
            {
                return false;
            }
        }
        return false;
    }

    bool operator != (const VertexIndexedData& rhs) const
    {
        if (PolygonIndex != rhs.PolygonIndex)
        {
            return true;
        }

        for (uint32 ui=0; ui < DaeIndexCount; ++ui)
        {
            uint32 uiThisIdx = DaeIndices[ui];
            uint32 uiRHSIdx = rhs.DaeIndices[ui];
            if (uiThisIdx != uiRHSIdx)
            {
                return true;
            }
        }
        return false;
    }

};

struct VertexIndexedDataSorter
{
    static bool LessThan(const VertexIndexedData* pLHS, const VertexIndexedData* pRHS)
    {
        return *pLHS < *pRHS;
    }
};

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void CreateIndices(uint16* pRBIndices, uint32* puiVertexCount, 
                   std::vector<VertexIndexedData*>& setSourcesIndices, 
                   VertexIndexedData* pDAEIndices, uint32 uiIndexCount)
{
    // Merge all vertices with same indices together, and assign the proper index
    std::sort(setSourcesIndices.begin(), setSourcesIndices.end(), VertexIndexedDataSorter::LessThan);

    std::vector<VertexIndexedData*>::iterator iter = setSourcesIndices.begin();
    VertexIndexedData* data = setSourcesIndices.front();
    uint16 uiNewIndex = 0;
    data->Duplicate = false;
    data->RBIndex = uiNewIndex;
    for (; iter != setSourcesIndices.end(); ++iter)
    {
        if (*data != *(*iter))
        {
            ++uiNewIndex;
            data = *iter;
            data->Duplicate = false;
        }
        (*iter)->RBIndex = uiNewIndex;
    }

    *puiVertexCount = uiNewIndex + 1;

    // Iterate though the index list and build the idnex buffer
    for (uint32 uiIndex=0; uiIndex<uiIndexCount; ++uiIndex)
    {
        VertexIndexedData& daeIdx = pDAEIndices[uiIndex];
        pRBIndices[uiIndex] = daeIdx.RBIndex;
    }
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
bool CreateGeometries(std::vector<RBGeometryHandle>& kGeometries,
                       const uint16* pIndices,
                       uint32 uiIndexCount,
                       const std::vector<uint32>& indexStarts,
                       const std::vector<uint32>& indexCounts,
                       const FCDGeometryMesh* pMesh, 
                       const std::vector<VertexIndexedData*>& setSourcesIndices, 
                       uint32 uiVertexCount,
                       RBRenderer* pRenderer)
{
    RBIndexBuffer* pIB = pRenderer->GetHBMgr()->CreateIndexBuffer(rb_hw_buffer_usage::HBU_DEFAULT, RBIndexBufferType::IT_16BIT, uiIndexCount, pIndices);

    // Guess how many elements will compose a vertex and what size a Vertex will be
    uint32 uiVertexElementCount = 0;
    uint32 uiVertexSize = 0;

    const FCDGeometryPolygons* pPolygons = setSourcesIndices[0]->Polygons;
    uint32 uiInputCount = pPolygons->GetInputCount();
    for (uint32 uiInput= 0; uiInput<uiInputCount; ++uiInput)
    {
        const FCDGeometryPolygonsInput* pInput = pPolygons->GetInput(uiInput);
        uint32 uiStride = pInput->GetSource()->GetStride();
        uiVertexSize += uiStride * sizeof(float32);
        ++uiVertexElementCount;
    }

    // Create elements description
    RBVertexElement* pElements = new RBVertexElement[uiVertexElementCount];
    uint32* auiVtxOffset = new uint32[uiVertexElementCount];
    uint32 uiOffset = 0;
    uint8 aUsageIndex[RBVertexElement::VEU_COUNT];
    memset(aUsageIndex, 0, RBVertexElement::VEU_COUNT);

    uint32 uiVertexElementIdx = 0;
    for (uint32 uiInput= 0; uiInput<uiInputCount; ++uiInput)
    {
        const FCDGeometryPolygonsInput* pInput = pPolygons->GetInput(uiInput);
        const FCDGeometrySource* pSource = pInput->GetSource();
        RBVertexElement::EUsage eVertexElementUsage;
        switch(pSource->GetType())
        {
        case FUDaeGeometryInput::POSITION:
            eVertexElementUsage = RBVertexElement::VEU_POSITION;
            break;
        case FUDaeGeometryInput::NORMAL:
            eVertexElementUsage = RBVertexElement::VEU_NORMAL;
            break;
        case FUDaeGeometryInput::GEOTANGENT:
        case FUDaeGeometryInput::TEXTANGENT:
            eVertexElementUsage = RBVertexElement::VEU_TANGENT;
            break;
        case FUDaeGeometryInput::GEOBINORMAL:
        case FUDaeGeometryInput::TEXBINORMAL:
            eVertexElementUsage = RBVertexElement::VEU_BITANGENT;
            break;
        case FUDaeGeometryInput::TEXCOORD:
            eVertexElementUsage = RBVertexElement::VEU_TEXCOORD;
            break;
        case FUDaeGeometryInput::COLOR:
            eVertexElementUsage = RBVertexElement::VEU_COLOR;
            break;
        case FUDaeGeometryInput::EXTRA:
            eVertexElementUsage = RBVertexElement::VEU_EXTRA;
            break;
        default:
            RBAssert(false, "Unsupported DAE source type format");
            eVertexElementUsage = RBVertexElement::VEU_POSITION;
            break;
        }
        RBVertexElement::EType eType = (RBVertexElement::EType)(RBVertexElement::VET_FLOAT1 + pSource->GetStride() - 1);
        pElements[uiVertexElementIdx].Stream        = 0;
        pElements[uiVertexElementIdx].Type          = eType;
        pElements[uiVertexElementIdx].Usage         = eVertexElementUsage;
        auiVtxOffset[uiVertexElementIdx] = uiOffset;

        ++uiVertexElementIdx;
        uiOffset += pSource->GetStride() * sizeof(float32);
    }

    uint8* pData = new uint8[uiVertexCount * uiVertexSize];

    std::vector<VertexIndexedData*>::const_iterator iter = setSourcesIndices.begin();

    for (; iter != setSourcesIndices.end(); ++iter)
    {
        const VertexIndexedData* vertexData = *iter;
        // We must put in VB at index vertexData.m_uiNewIndex all the data of all inputs potentially indexed
        if (vertexData->Duplicate)
        {
            continue;
        }

        uint8* pStartData = &pData[vertexData->RBIndex * uiVertexSize];
        for (uint32 uiInput= 0; uiInput<uiInputCount; ++uiInput)
        {
            // Retrieve source data index
            RBAssert(uiInput <  vertexData->Polygons->GetInputCount(), "unsupported geometry type");
            uint32 uiSrcDataIdx = vertexData->DaeIndices[uiInput];
            const FCDGeometryPolygonsInput* pInput = vertexData->Polygons->GetInput(uiInput);
            const FCDGeometrySource* pSource = pInput->GetSource();
            const float* pSrcData = pSource->GetData();
            uint32 uiSizeToCopy = pSource->GetStride() * sizeof(float32);
            memcpy_s(&pStartData[auiVtxOffset[uiInput]], uiSizeToCopy, &pSrcData[pSource->GetStride() * uiSrcDataIdx], uiSizeToCopy);
        }
    }


    RBVertexBuffer* pVB = pRenderer->GetHBMgr()->CreateVertexBuffer(rb_hw_buffer_usage::HBU_DEFAULT, uiVertexSize, uiVertexCount, pData);
    RBVertexDeclaration* pVDecl = pRenderer->GetHBMgr()->CreateVertexDeclaration(pElements, uiVertexElementCount, NULL);
    delete[] auiVtxOffset;
    delete[] pElements;
    delete[] pData;

    // For each polygon set, create a separate Vertex and index data
    uint32 uiPolygonCount = pMesh->GetPolygonsCount();
    for (uint32 uiPolygonIdx = 0; uiPolygonIdx < uiPolygonCount; ++uiPolygonIdx)
    {
        RBGeometryHandle pGeom = RBGeometry::Create(InvalidHandle);
        pGeom->SetVertexData(pVDecl, pVB, uiVertexCount);
        pGeom->SetIndexData(pIB, indexCounts[uiPolygonIdx], indexStarts[uiPolygonIdx]);
#pragma TODO("Support something else than triangle list")
        pGeom->SetPrimitiveType(RBGeometryPrimitiveType::TRIANGLELIST);
        kGeometries.push_back(pGeom);

    }


    return true;
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void RBDAEReader::CreateObjectFromGeometry(const FCDGeometry* pGeom, RBRenderer* pRenderer)
{
    if (!pGeom)
    {
        return;
    }

    const FCDGeometryMesh* pMesh = pGeom->GetMesh();

#pragma TODO("deal with non triangulated meshes")
    if (!pMesh || !pMesh->IsTriangles())
    {
        return;
    }

#pragma TODO("deal with geometries that don't have the same vertex declaration for 2 polygon sets")

    // Guess how many triangles we will have for this geometry set
    std::vector<VertexIndexedData*> kVertices;
    VertexIndexedData* pVertexData = 0;
    uint32 uiPolygonCount = pMesh->GetPolygonsCount();
    uint32 uiIndexCount = 0;
    std::vector<uint32> kIndexStarts;
    std::vector<uint32> kIndexCounts;
    uint32 uiDAEIndexCount = 0;
    for (uint32 uiPolygonSet = 0; uiPolygonSet < uiPolygonCount; ++uiPolygonSet)
    {
        const FCDGeometryPolygons* pPolygons = pMesh->GetPolygons(uiPolygonSet);
        uint32 uiPolygonIndexCount = 3*pPolygons->GetFaceCount();

        kIndexStarts.push_back(uiIndexCount);
        kIndexCounts.push_back(uiPolygonIndexCount);

        uiIndexCount += uiPolygonIndexCount;
        uint32 uiInputCount = pPolygons->GetInputCount();
        uint32 uiCheck = 0;
        
        uiDAEIndexCount += uiInputCount * uiPolygonIndexCount;

        // Sanity check for index count
        for (uint32 uiInput = 0; uiInput < uiInputCount; ++uiInput)
        {
            const FCDGeometryPolygonsInput* pInput = pPolygons->GetInput(uiInput);
            uiCheck = pInput->GetIndexCount();
            RBAssert(uiCheck == uiPolygonIndexCount, "Inconsistent mesh !");
        }
    }

    uint32* pDAEIndices = new uint32[uiDAEIndexCount];
    uint32* pCurIndex = pDAEIndices;
    pVertexData = new VertexIndexedData[uiIndexCount];
    kVertices.resize(uiIndexCount);
    // Retrieve indexed information per vertex
    uint32 uiRBVtxIdx = 0;
    for (uint32 uiPolygonSet = 0; uiPolygonSet < uiPolygonCount; ++uiPolygonSet)
    {
        const FCDGeometryPolygons* pPolygons = pMesh->GetPolygons(uiPolygonSet);
        uint32 uiDAEIndexCount = 3*pPolygons->GetFaceCount();
        uint32 uiInputCount = pPolygons->GetInputCount();
        for (uint32 uiIdx = 0; uiIdx < uiDAEIndexCount; ++uiIdx)
        {
            VertexIndexedData& kIndexedVertex = pVertexData[uiRBVtxIdx];
            kIndexedVertex.Polygons = pPolygons;
            kIndexedVertex.DaeIndexCount = pPolygons->GetInputCount();
            kIndexedVertex.DaeIndices = pCurIndex;
            pCurIndex += pPolygons->GetInputCount();
            kIndexedVertex.PolygonIndex = (uint16)uiPolygonSet;
            for (uint32 uiInput = 0; uiInput < uiInputCount; ++uiInput)
            {
                const FCDGeometryPolygonsInput* pInput = pPolygons->GetInput(uiInput);
                kIndexedVertex.DaeIndices[uiInput] = pInput->GetIndices()[uiIdx];
            }
            kVertices[uiRBVtxIdx] = &pVertexData[uiRBVtxIdx];
            ++uiRBVtxIdx;
        }
    }

    // Sort this information to avoid duplicated vertices
    uint32 uiVertexCount;
    uint16* pRBIndices = new uint16[uiIndexCount];
    CreateIndices(pRBIndices, &uiVertexCount, kVertices, pVertexData, uiIndexCount);

    // Create the associated render buffers
    std::vector<RBGeometryHandle> aGeometries;
    CreateGeometries(aGeometries, pRBIndices, uiIndexCount, kIndexStarts, kIndexCounts, pMesh, 
                     kVertices, uiVertexCount, pRenderer);

    delete[] pDAEIndices;
    delete[] pVertexData;

    RBGeometryMultiSub rbGeom;
    RBAssert(aGeometries.size() == uiPolygonCount, "Inconsistent number of geometries created");
    for (uint32 ui=0; ui < uiPolygonCount; ++ui)
    {
        rbGeom.m_mPolygons[pMesh->GetPolygons(ui)] = aGeometries[ui];
    }
    m_mGeometries[pGeom] = rbGeom;
}

static inline RBSamplerState::FilterMode FCDToRBFilterMode(FUDaeTextureFilterFunction::FilterFunction eFilter)
{
    return RBSamplerState::SFM_LINEAR;
/*
    switch(eFilter)
    {
    case FUDaeTextureFilterFunction::NONE:
    case FUDaeTextureFilterFunction::NEAREST:
    case FUDaeTextureFilterFunction::LINEAR:
        return (RBSamplerState::FilterMode) eFilter;
    default:
        break;
    }
    return RBSamplerState::SFM_LINEAR;
*/
}

static inline RBSamplerState::AdressMode FCDToRBAdressMode(FUDaeTextureWrapMode::WrapMode eMode)
{
    switch (eMode)
    {
    case FUDaeTextureWrapMode::WRAP:
        return RBSamplerState::SAM_WRAP;
    case FUDaeTextureWrapMode::MIRROR:
        return RBSamplerState::SAM_MIRROR;
    case FUDaeTextureWrapMode::CLAMP:
        return RBSamplerState::SAM_CLAMP;
    case FUDaeTextureWrapMode::BORDER:
        return RBSamplerState::SAM_BORDER;
    default:
        break;
    }
    return RBSamplerState::SAM_WRAP;
}

static inline void ApplySamplers(RBMaterial* material, const RBStringID& string_id, const RBStringID& default_texture, const FCDEffectStandard* pFCDEffectProfile, 
                                 FUDaeTextureChannel::Channel eChannel)
{
    const char* file_name = 0;

    RBTextureSampler& sampler = material->DataContainer.GetSampler(string_id + "_sampler");
    if (pFCDEffectProfile->GetTextureCount(eChannel) > 0)
    {
        // If there is a slot inside the texture, use it

        const FCDTexture* fcdTexture = pFCDEffectProfile->GetTexture(eChannel, 0);
        file_name = fcdTexture->GetImage()->GetFilename().c_str();
        
        const FCDEffectParameterSampler* pFCDSampler = fcdTexture->GetSampler();
        sampler.MagFilter = FCDToRBFilterMode(pFCDSampler->GetMagFilter());
        sampler.MinFilter = FCDToRBFilterMode(pFCDSampler->GetMinFilter());
        sampler.MipFilter = FCDToRBFilterMode(pFCDSampler->GetMipFilter());
        sampler.U = FCDToRBAdressMode(pFCDSampler->GetWrapS());
        sampler.V = FCDToRBAdressMode(pFCDSampler->GetWrapT());
        sampler.W = FCDToRBAdressMode(pFCDSampler->GetWrapP());
    }
    else
    {
        file_name = default_texture.c_str();
    }

    RBShaderResourceView* resource_view = RBRenderer::GetSingleton()->GetHBMgr()->CreateShaderResourceView(RBResourceManager::GetSingleton()->GetTexture(file_name));
    material->DataContainer.AddView(string_id + "_texture", resource_view);
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void RBDAEReader::CreateMaterialFromMaterial(const FCDMaterial* pFCDMaterial, RBRenderer*)
{
    const FCDEffect* pFCDEffect = pFCDMaterial->GetEffect();
    // We retrieve only profile common atm: we will probably use shaders, but not in collada's way
    const FCDEffectStandard* pFCDEffectProfile = (const FCDEffectStandard*)pFCDEffect->FindProfile(FUDaeProfileType::COMMON);
    RBAssert(pFCDEffectProfile, "No common profile found for effect !");
    if (!pFCDEffectProfile)
    {
        return;
    }

    RBMaterial* pMaterial = new RBMaterial;
    
    pMaterial->Ambient   = (Convert<3, RBColor>(pFCDEffectProfile->GetAmbientColor()));

    pMaterial->Diffuse   = (Convert<3, RBColor>(pFCDEffectProfile->GetDiffuseColor()));

    pMaterial->Specular  = (Convert<3, RBColor>(pFCDEffectProfile->GetSpecularColor() * pFCDEffectProfile->GetSpecularFactor()));

    pMaterial->Emissive  = (Convert<3, RBColor>(pFCDEffectProfile->GetEmissionColor()));

    pMaterial->Opacity   = (pFCDEffectProfile->GetOpacity());

    pMaterial->Shininess = (pFCDEffectProfile->GetShininess());

    pMaterial->SetEffect(RBEffectFactory::GetSingleton()->RetrieveEffect("test"));

#pragma TODO("Deal with IFL properly")

    ApplySamplers(pMaterial, "diffuse", "./Data/default-albedo.png", pFCDEffectProfile, FUDaeTextureChannel::DIFFUSE);
    ApplySamplers(pMaterial, "normal", "./Data/default-normal.png", pFCDEffectProfile, FUDaeTextureChannel::BUMP);
    ApplySamplers(pMaterial, "specular", "./Data/default-albedo.png", pFCDEffectProfile, FUDaeTextureChannel::SPECULAR);

    m_mMaterials[pFCDMaterial] = pMaterial;

}

void RBDAEReader::AddGeometryInstance(RBEntityHandle entityHandle, RBTransformComponentHandle xFormHandle, FCDGeometry* pFCDGeometry, FCDGeometryInstance* pFCDGeometryInstance)
{
    GeometryMap::iterator iter = m_mGeometries.find(pFCDGeometry);
    if (iter == m_mGeometries.end())
    {
        return;
    }

    // We found something

    RBEntity& entity = RBEntity::Get(entityHandle);

    RBGeometryMultiSub& rbGeomMultiSub = iter->second;

    for (uint32 ui=0; ui < pFCDGeometryInstance->GetMaterialInstanceCount(); ++ui)
    {
        FCDMaterialInstance* pMaterialInstance = pFCDGeometryInstance->GetMaterialInstance(ui);
        const FCDGeometryPolygons* pObject = (const FCDGeometryPolygons*)pMaterialInstance->GetGeometryTarget();
        //RBGeometryPtr pNewGeom = pScene->GetLibrary<RBGeometry>()->AddEntity();
        RBHandle<RBGeometry> pSrcGeom = rbGeomMultiSub.m_mPolygons[pObject];
        RBMaterial* pMaterial = m_mMaterials[pMaterialInstance->GetMaterial()];
        if (!pMaterial)
        {
            //pMaterial = pScene->GetLibrary<RBMaterial>()->AddEntity(); 
            pMaterial = new RBMaterial;
        }
        RBHandle<RBGeometry> newGeomHandle = RBGeometry::Create(entityHandle, xFormHandle);

        RBHandle<RBBVolume> hVolume = RBBVolume::Create(entityHandle, xFormHandle);
        hVolume->ComputeFromData(pFCDGeometry->GetMesh()->GetPositionSource()->GetData(), pFCDGeometry->GetMesh()->GetPositionSource()->GetDataCount()/3);
        hVolume->SetObject(RBGeometry::GetClassIdx(), newGeomHandle);

        pSrcGeom->CopyMembers(newGeomHandle);
        newGeomHandle->SetMaterial(pMaterial);
        entity.AddComponent<RBGeometry>(newGeomHandle);
        entity.AddComponent<RBBVolume>(hVolume);

    }
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void RBDAEReader::AddCamera(RBEntityHandle entityHandle, RBTransformComponentHandle xFormHandle, FCDCamera* pFCDCamera)
{
    float32 fValue = 0;

    bool bOrtho = (pFCDCamera->GetProjectionType() == FCDCamera::ORTHOGRAPHIC);

    if (bOrtho)
    {
        if (pFCDCamera->HasHorizontalMag())
        {
            fValue = pFCDCamera->GetMagX();
        }
        else if (pFCDCamera->HasHorizontalMag())
        {
            float32 fMagY = pFCDCamera->GetMagX();
            fValue = fMagY / pFCDCamera->GetAspectRatio();
        }
        else
        {
            RBAssert(false, "Camera doesn't define horz MAG nor vert MAG");
        }
    }
    else if (pFCDCamera->HasHorizontalFov())
    {
        fValue = RBMath::ToRadian((float32)pFCDCamera->GetFovX());
    }
    else if (pFCDCamera->HasVerticalFov())
    {
        float32 fFovY = RBMath::ToRadian((float32)pFCDCamera->GetFovY());
        fValue = fFovY / pFCDCamera->GetAspectRatio();
    }
    else
    {
        RBAssert(false, "Camera doesn't define horz FOV nor vert FOV");
    }

    RBEntity& entity = RBEntity::Get(entityHandle);
    
    RBHandle<RBCamera> pDstCamera = RBCamera::Create(entityHandle, xFormHandle);
    pDstCamera->SetViewFrustum(fValue, pFCDCamera->GetAspectRatio(), pFCDCamera->GetNearZ(), 
        pFCDCamera->GetFarZ(), bOrtho);

    entity.AddComponent<RBCamera>(pDstCamera);
    
}

/**************************************************************************************************************************************************************
 * 
 **************************************************************************************************************************************************************/
void RBDAEReader::AddLight(RBEntityHandle entityHandle, RBTransformComponentHandle xFormHandle, FCDLight* pFCDLight)
{
    //RBLight* pDstLight = pScene->GetLibrary<RBLight>()->AddEntity();
    RBHandle<RBLight> pDstLight = RBLight::Create(entityHandle, xFormHandle);
    FMVector3 srcColor = pFCDLight->GetColor();
    pDstLight->SetColor(RBColor(srcColor.x, srcColor.y, srcColor.z));
    switch(pFCDLight->GetLightType())
    {
    case FCDLight::AMBIENT:
        pDstLight->SetType(RBLight::LT_AMBIENT);
        break;
    case FCDLight::DIRECTIONAL:
        pDstLight->SetType(RBLight::LT_DIRECTIONAL);
        break;
    case FCDLight::SPOT:
        pDstLight->SetType(RBLight::LT_SPOT);
        break;
    case FCDLight::POINT:
        pDstLight->SetType(RBLight::LT_POINT);
        break;
    default:
        break;
    }

    pDstLight->SetMultiplier(pFCDLight->GetIntensity());

    pDstLight->SetConstantAttenuation(pFCDLight->GetConstantAttenuationFactor());
    pDstLight->SetLinearAttenuation(pFCDLight->GetLinearAttenuationFactor());
    pDstLight->SetQuadraticAttenuation(pFCDLight->GetQuadraticAttenuationFactor());
    pDstLight->SetQuadraticAttenuation(80.0f);

    pDstLight->SetPenumbraAngle(pFCDLight->GetFallOffAngle());
    pDstLight->SetUmbraAngle(pFCDLight->GetOuterAngle());
    pDstLight->SetFalloff(pFCDLight->GetFallOffExponent());

    RBEntity& entity = RBEntity::Get(entityHandle);

    entity.AddComponent<RBLight>(pDstLight);

}
/***********************************************************************************************************/
